#pragma once

#include <iostream>
#include <pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include <queue>

using namespace std;

size_t DefaultCapacity = 5;

template <typename T>
class BlockQueue
{
private:
    bool isQueueFull()
    {
        return _capacity == _bq.size();
    }

    bool isQueueEmpty()
    {
        return _bq.size() == 0;
    }

public:
    BlockQueue(size_t capacity = DefaultCapacity)
        : _capacity(capacity)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_empty, nullptr);
        pthread_cond_init(&_full, nullptr);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_empty);
        pthread_cond_destroy(&_full);
    }

    // 生产者：存放资源
    void Push(const T &in)
    {
        pthread_mutex_lock(&_mutex);
        while (isQueueFull())
        {
            pthread_cond_wait(&_full, &_mutex);
        }
        _bq.push(in);
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_empty);
    }

    // 消费者：取出资源
    void Pop(T *out)
    {
        pthread_mutex_lock(&_mutex);
        while(isQueueEmpty())
        {
            pthread_cond_wait(&_empty,&_mutex);
        }
        *out = _bq.front();
        _bq.pop();
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_full);
    }

private:
    queue<T> _bq;           // 共享区
    size_t _capacity;       // 队列的容量上限
    pthread_mutex_t _mutex; // 锁
    pthread_cond_t _empty;  // 消费者的条件变量
    pthread_cond_t _full;   // 生产者的条件变量
};